﻿/************************************************************************
 * author:漠然 2013年7月12日4:25:15
 * **********************************************************************/

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Xml;

namespace Mrsoft.Model {
    /// <summary>
    /// 负责对数据进行解析
    /// </summary>
    public class GameDataManager {
        /// <summary>
        /// 数据解析结果集
        /// </summary>
        Dictionary<string, DataInfo> DataDic;

        /// <summary>
        /// 对XML数据进行初步分析
        /// </summary>
        private void XmlAnalys(XmlDocument xDoc) {
            var selectSingleNode = xDoc.SelectSingleNode("//Data");
            if (selectSingleNode != null) {
                XmlNodeList xNodes = selectSingleNode.ChildNodes;
                if (DataDic == null)
                    DataDic = new Dictionary<string, DataInfo>(xNodes.Count);
                else
                    DataDic.Clear();
                foreach (XmlElement xElement in xNodes) {
                    var theData = new DataInfo {
                        Name = xElement.GetAttribute("name"),
                        Value =
                            int.Parse(xElement.GetAttribute("value").Replace("0x", ""), NumberStyles.AllowHexSpecifier)
                    };
                    string binaryStr = xElement.GetAttribute("binary");
                    if (!string.IsNullOrEmpty(binaryStr)) {
                        var binaryList = new List<byte>();
                        for (int i = 0; i < binaryStr.Length; ) {
                            binaryList.Add(Convert.ToByte(byte.Parse(binaryStr.Substring(i, 2), NumberStyles.AllowHexSpecifier)));
                            i += 2;
                        }
                        theData.AsmCode = binaryList.ToArray();
                        theData.Offset = short.Parse(xElement.GetAttribute("off").Replace("0x", ""), NumberStyles.AllowHexSpecifier);
                        theData.Data = (DataType)int.Parse(xElement.GetAttribute("type"));
                    }
                    else {
                        theData.Parent = xElement.GetAttribute("parent");
                    }
                    DataDic.Add(theData.Name, theData);
                }
            }
        }

        /// <summary>
        /// 对数据进行内存分析
        /// </summary>
        /// <param name="theData"></param>
        /// <param name="memDataArr"></param>
        /// <param name="memDataSta"></param>
        private void MemAnalys(DataInfo theData, byte[] memDataArr, Int32 memDataSta) {
            if (theData.AsmCode == null)
                return;
            int asmIndex = 0;
            for (int index = 0; index < memDataArr.Length; index++) {
                if (memDataArr[index] == theData.AsmCode[asmIndex]) {
                    for (asmIndex = 1; asmIndex < theData.AsmCode.Length; asmIndex++) {
                        if (memDataArr[index + asmIndex] != theData.AsmCode[asmIndex]) {
                            asmIndex = 0;
                            break;
                        }
                    }
                    if (asmIndex == 0)
                        continue;
                    int addIndex = index + theData.Offset;
                    int temValue = addIndex;

                    switch (theData.Data) {
                        case DataType.DirectAddressPointer:
                            temValue += memDataSta;
                            break;
                        case DataType.DataDirInThatPointer:
                            temValue = BitConverter.ToInt32(memDataArr, addIndex);
                            break;
                        case DataType.RelatiAddressPointer:
                            temValue = BitConverter.ToInt32(memDataArr, addIndex);
                            temValue += addIndex + 4;
                            temValue += memDataSta;
                            break;
                    }
                    //Console.WriteLine("解析结果：{0}\t\t\t{1}对应的内存地址为{2}", theData.Name, temValue.ToString("X"), memDataSta + index + theData.Offset);
                    theData.ValueChange = temValue - theData.Value;
                    theData.Value = temValue;
                    return;
                }
            }
            throw new Exception(string.Format("{0}进行关联解码失败！", theData.Name));
        }

        /// <summary>
        /// 对通过类偏移来识别的数据进行识别赋值
        /// </summary>
        /// <param name="theData"></param>
        private void GetChildData(DataInfo theData) {
            if (!string.IsNullOrEmpty(theData.Parent))
                theData.Value += DataDic[theData.Parent].ValueChange;
        }

        /// <summary>
        /// 数据分析
        /// </summary>
        public void Analys(XmlDocument xDoc, Int32 memDataSta, byte[] memDataArr) {
            XmlAnalys(xDoc);
            foreach (KeyValuePair<string, DataInfo> tem in DataDic) {
                MemAnalys(tem.Value, memDataArr, memDataSta);
            }
            foreach (KeyValuePair<string, DataInfo> tem in DataDic) {
                GetChildData(tem.Value);
            }
        }

        /// <summary>
        /// 利用反射的方式讲数据进行相应绑定
        /// </summary>
        /// <param name="temObj"></param>
        /// <param name="savefileName"></param>
        /// <returns></returns>
        public bool GetData<T>(T temObj, string savefileName) {
            //使用反射技术将数据映射到传入的实例对应字段
            foreach (KeyValuePair<string, DataInfo> tem in DataDic) {
                try {
                    temObj.GetType()
                        .InvokeMember(tem.Value.Name.Trim(), BindingFlags.SetField, null, temObj,
                            new object[] { tem.Value.Value });
                }
                catch (MissingFieldException ex) {
                    Mrsoft.Common.MsgListener.CommonMsgShow("数据解析", ex.Message);
                }
            }
            //检查序列化路径
            var savePath = savefileName.Replace("\\", "/");
            savePath = savePath.Remove(savePath.LastIndexOf("/", StringComparison.Ordinal) + 1);
            if (Directory.Exists(savePath))
                Directory.CreateDirectory(savePath);
            var str = Newtonsoft.Json.JsonConvert.SerializeObject(temObj);
            File.WriteAllText(savefileName, str);
            return true;
        }

        class DataInfo {
            //必须数据
            public string Name;
            public int Value;
            //同类变换
            public string Parent;
            public int ValueChange;
            //二进制特征码寻址
            public DataType Data;
            public byte[] AsmCode;
            public int Offset;
        }


        /// <summary>
        /// 等待的解析的数据的类型
        /// 用于判定解析方法
        /// </summary>
        enum DataType {
            /// <summary>
            /// 直接返回内存地址
            /// </summary>
            DirectAddressPointer = 0,
            /// <summary>
            /// 返回内存地址和内存中的值日计算而出的相对内存地址
            /// </summary>
            RelatiAddressPointer = 1,
            /// <summary>
            /// 直接返回内存中的值
            /// </summary>
            DataDirInThatPointer = 2
        }
    }
}
